package org.itzixi.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.itzixi.netty.http.HttpServerInitializer;
import org.itzixi.netty.mq.RabbitMQConnectUtils;
import org.itzixi.netty.utils.JedisPoolUtils;
import org.itzixi.netty.utils.ZookeeperRegister;
import org.itzixi.netty.websocket.WSServerInitializer;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Netty 聊天服务器
 */
public class ChatServer {

    public static final Integer nettyDefaultPort = 875;
    private static final String initOnlineCounts = "0";
    public static Integer selectPort(Integer port) {
        String portKey = "netty_port";
        Jedis jedis = JedisPoolUtils.getJedis();
        Map<String, String> portMap = jedis.hgetAll(portKey);
//        System.out.println(portMap);

        List<Integer> portList = portMap
                .entrySet()
                .stream()
                .map(entry -> Integer.valueOf(entry.getKey()))
                .collect(Collectors.toList());

        System.out.println(portList);
        Integer nettyPort = null;
        if (portList == null || portList.isEmpty()) {
            jedis.hset(portKey, port.toString(), initOnlineCounts);
            nettyPort = port;
        } else {
            Optional<Integer> maxInteger = portList.stream().max(Integer::compareTo);
            Integer maxPort = maxInteger.get().intValue();
            Integer currentPort = maxPort + 10;
            jedis.hset(portKey, currentPort.toString(), initOnlineCounts);
            nettyPort = currentPort;
        }
        return nettyPort;
    }

    public static void main(String[] args) throws Exception{
        //定义主从线程组
        //定义主线程组 用于接收客户端连接 不做业务操作
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //定义从线程组 用于处理主线程池分配的任务
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // Netty服务启动的时候，从redis中查找有没有端口，如果没有，则使用875，如果有，则使用最大端口+10
        Integer nettyPort = selectPort(nettyDefaultPort);

        // 将Netty服务器节点信息注册到Zookeeper上
        ZookeeperRegister.registerNettyServer("server-list",
                                                    ZookeeperRegister.getLocalIp(),
                                                        nettyPort);

        // 启动消费者进行监听，队列可以根据动态生成的端口进行动态拼接
        String queueName = "netty_queue_" + nettyPort;
        RabbitMQConnectUtils mqConnectUtils = new RabbitMQConnectUtils();
        mqConnectUtils.listen("fanout_exchange_imooc", queueName);

        try {
            //构建Netty服务器
            ServerBootstrap server = new ServerBootstrap();         //服务启动类
            server.group(bossGroup, workerGroup)                    //设置主从线程组
                    .channel(NioServerSocketChannel.class)          //设置NIO的双向通道
                    .childHandler(new WSServerInitializer());       //设置子处理器 用于处理workerGroup的任务

            //启动服务器 绑定端口号875 启动方式为同步
            ChannelFuture channelFuture = server.bind(nettyPort).sync(); //绑定端口
            System.out.println("Netty Chat Server 启动完毕...");
            //请求 http:127.0.0.1:875

            //监听关闭事件
            channelFuture.channel().closeFuture().sync();
        } finally {
            //优雅关闭 释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
